package psd.model.Prolog.Converters;


import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.jdt.core.dom.Comment;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.IExtendedModifier;
import org.eclipse.jdt.core.dom.Javadoc;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;

// Referenced classes of package org.cs3.jtransformer.internal.astvisitor:
//            DescendingIntComparator

public class CommentHelper
{

    private ICompilationUnit iCompilationUnit;
    private String sourceString;
    private static Pattern lineSeparatorPattern = Pattern.compile(System.getProperty("line.separator"));
    private HashMap equivalentKeysLeft;
    private HashMap equivalentKeysRight;

    public CommentHelper(ICompilationUnit compilationUnit)
    {
        equivalentKeysLeft = new HashMap();
        equivalentKeysRight = new HashMap();
        iCompilationUnit = compilationUnit;
        try
        {
            sourceString = iCompilationUnit.getSource();
        }
        catch(JavaModelException e)
        {
           // JTDebug.error((new StringBuilder("Retrieving the string representation of ")).append(iCompilationUnit.getPath()).append(": ").append(e.getCause()).toString());
        }
    }

    public int[] excludeComments(ASTNode node)
    {
        Javadoc docnode = null;
        List modList = null;
        if(node instanceof AbstractTypeDeclaration)
        {
            node = (AbstractTypeDeclaration)node;
            docnode = ((AbstractTypeDeclaration)node).getJavadoc();
            modList = ((AbstractTypeDeclaration)node).modifiers();
        } else
        if(node instanceof MethodDeclaration)
        {
            node = (MethodDeclaration)node;
            docnode = ((MethodDeclaration)node).getJavadoc();
            modList = ((MethodDeclaration)node).modifiers();
        } else
        if(node instanceof FieldDeclaration)
        {
            node = (FieldDeclaration)node;
            docnode = ((FieldDeclaration)node).getJavadoc();
            modList = ((FieldDeclaration)node).modifiers();
        }
        if((node instanceof AbstractTypeDeclaration) | (node instanceof MethodDeclaration) | (node instanceof FieldDeclaration))
        {
            if(docnode != null)
            {
                if(modList.size() != 0)
                {
                    IExtendedModifier firstModType = (IExtendedModifier)modList.get(0);
                    if(firstModType.isModifier())
                    {
                        Modifier modifier = (Modifier)firstModType;
                        String modifierString = modifier.getKeyword().toString();
                        int javaDocEnd = docnode.getLength() + docnode.getStartPosition();
                        int pureStart = sourceString.indexOf(modifierString, javaDocEnd);
                        int lengthToRemove = pureStart - node.getStartPosition();
                        int pureLength = node.getLength() - lengthToRemove;
                        return (new int[] {
                            pureStart, pureLength
                        });
                    } else
                    {
                        return (new int[] {
                            node.getStartPosition(), node.getLength()
                        });
                    }
                }
                int javaDocEnd = docnode.getLength() + docnode.getStartPosition();
                if(node instanceof AbstractTypeDeclaration)
                {
                    int indexOfClass = sourceString.indexOf("class", javaDocEnd);
                    int indexOfInterface = sourceString.indexOf("interface", javaDocEnd);
                    int pureStart;
                    if(indexOfClass == -1)
                    {
                        pureStart = indexOfInterface;
                    } else
                    {
                        pureStart = indexOfClass;
                    }
                    int lengthToRemove = pureStart - node.getStartPosition();
                    int pureLength = node.getLength() - lengthToRemove;
                    return (new int[] {
                        pureStart, pureLength
                    });
                }
                if(node instanceof FieldDeclaration)
                {
                    List fragList = ((FieldDeclaration)node).fragments();
                    String returnType = ((VariableDeclarationFragment)fragList.get(0)).resolveBinding().getType().getName();
                    int indexOfType = sourceString.indexOf(returnType, javaDocEnd);
                    int lengthToRemove = indexOfType - node.getStartPosition();
                    int pureLength = node.getLength() - lengthToRemove;
                    return (new int[] {
                        indexOfType, pureLength
                    });
                }
                if(node instanceof MethodDeclaration)
                {
                    String returnType = ((MethodDeclaration)node).resolveBinding().getReturnType().getName();
                    int indexOfType = sourceString.indexOf(returnType, javaDocEnd);
                    int lengthToRemove = indexOfType - node.getStartPosition();
                    int pureLength = node.getLength() - lengthToRemove;
                    return (new int[] {
                        indexOfType, pureLength
                    });
                } else
                {
                    return null;
                }
            } else
            {
                return (new int[] {
                    node.getStartPosition(), node.getLength()
                });
            }
        } else
        {
            return (new int[] {
                node.getStartPosition(), node.getLength()
            });
        }
    }

    public int getDistanceToTheRight(Comment node)
    {
        return getNextElementOffset(node);
    }

    public int getDistanceToTheLeft(Comment node)
    {
        int searchStartPosition;
        if(node.getStartPosition() != 0)
        {
            searchStartPosition = node.getStartPosition() - 1;
        } else
        {
            searchStartPosition = 0;
        }
        int nodeStartPosition = node.getStartPosition();
        int distanceToTheLeft = 0;
        System.getProperty("line.separator");
        for(; Character.isWhitespace(sourceString.charAt(searchStartPosition - distanceToTheLeft)); distanceToTheLeft++) { }
        return nodeStartPosition - distanceToTheLeft;
    }

    protected int getNextElementOffset(Comment node)
    {
        int startPosition = node.getStartPosition();
        int endPosition = startPosition + node.getLength();
        int i;
        for(i = 0; Character.isWhitespace(sourceString.charAt(endPosition + i)); i++)
        {
            if(sourceString.length() <= endPosition + i + 1)
            {
                break;
            }
        }

        int nextElementPosition = endPosition + i;
        return nextElementPosition;
    }

    public void resolveTransitiveCommentRelations(HashMap hashmap, HashMap hashmap1, List list)
    {
    }

    public void decideOwner(HashMap resolvedTableLeft, HashMap resolvedTableRight)
    {
        Integer keysLeft[] = new Integer[0];
        keysLeft = (Integer[])equivalentKeysLeft.keySet().toArray(keysLeft);
        Integer ainteger[];
        int j = (ainteger = keysLeft).length;
        for(int i = 0; i < j; i++)
        {
            Integer keyLeft = ainteger[i];
            Integer keyRight = (Integer)equivalentKeysLeft.get(keyLeft);
            List tempRight = (List)resolvedTableRight.get(keyRight);
            List tempLeft = (List)resolvedTableLeft.get(keyLeft);
            if((tempRight != null) & (tempLeft != null))
            {
                Integer minStartingPosition = minimumStart(tempLeft);
                String distanceStringLeft = sourceString.substring(keyLeft.intValue(), minStartingPosition.intValue());
                Integer linesLeft = Integer.valueOf(countLineSeparators(distanceStringLeft));
                Integer maxEndingPosition = maximumEnd(tempRight);
                String distanceStringRight = sourceString.substring(maxEndingPosition.intValue(), keyRight.intValue());
                Integer linesRight = Integer.valueOf(countLineSeparators(distanceStringRight));
                if(linesLeft.intValue() < linesRight.intValue())
                {
                    resolvedTableRight.remove(keyRight);
                } else
                if(linesLeft.intValue() > linesRight.intValue())
                {
                    resolvedTableLeft.remove(keyLeft);
                } else
                if(linesLeft == linesRight)
                {
                    resolvedTableLeft.remove(keyLeft);
                }
            } else
            if(tempRight == null);
        }

    }

    public Integer maximumEnd(List commentList)
    {
        Integer maxEndingPosition = null;
        for(Iterator iterator = commentList.iterator(); iterator.hasNext();)
        {
            Comment comment = (Comment)iterator.next();
            int commentEnd = comment.getStartPosition() + comment.getLength();
            if(maxEndingPosition == null)
            {
                maxEndingPosition = Integer.valueOf(commentEnd);
            }
            maxEndingPosition.intValue();
            if(maxEndingPosition.intValue() < commentEnd)
            {
                maxEndingPosition = Integer.valueOf(commentEnd);
            }
        }

        return maxEndingPosition;
    }

    public Integer minimumStart(List commentList)
    {
        Integer minStartingPosition = null;
        for(Iterator iterator = commentList.iterator(); iterator.hasNext();)
        {
            Comment comment = (Comment)iterator.next();
            if(minStartingPosition == null)
            {
                minStartingPosition = Integer.valueOf(comment.getStartPosition());
            }
            minStartingPosition.intValue();
            comment.getStartPosition();
            if(minStartingPosition.intValue() > comment.getStartPosition())
            {
                minStartingPosition = Integer.valueOf(comment.getStartPosition());
            }
        }

        return minStartingPosition;
    }

    private HashMap invertHashtable(HashMap commentTableRightInverted)
    {
        Set set = commentTableRightInverted.entrySet();
        Iterator iterator = set.iterator();
        HashMap invertedTable = new HashMap();
        Object value;
        Object key;
        for(; iterator.hasNext(); invertedTable.put(value, key))
        {
            java.util.Map.Entry currentTableEntry = (java.util.Map.Entry)iterator.next();
            value = currentTableEntry.getValue();
            key = currentTableEntry.getKey();
        }

        return invertedTable;
    }

    public int countLineSeparators(String string)
    {
        Matcher m = lineSeparatorPattern.matcher(string);
        int count;
        for(count = 0; m.find(); count++) { }
        return count;
    }

    public void resolvedTransitiveRelationsLeft(HashMap leftInverted)
    {
        Integer keyList[] = new Integer[0];
        keyList = (Integer[])leftInverted.keySet().toArray(keyList);
        Arrays.sort(keyList, new DescendingIntComparator());
        Integer ainteger[];
        int j = (ainteger = keyList).length;
        for(int i = 0; i < j; i++)
        {
            Integer key = ainteger[i];
            HashMap commentRearangeTable = new HashMap();
            List keysToBeDeleted = new ArrayList();
            Comment comAr[] = new Comment[0];
            comAr = (Comment[])((List)leftInverted.get(key)).toArray(comAr);
            List commentList = (List)leftInverted.get(key);
            Comment acomment[];
            int l = (acomment = comAr).length;
            for(int k = 0; k < l; k++)
            {
                Comment comment = acomment[k];
                int commentEndPosition = comment.getStartPosition() + comment.getLength();
                List commentsWithCurrentCommentToTheLeft = (List)leftInverted.get(Integer.valueOf(commentEndPosition));
                int rightCommentStart = 0;
                if(commentsWithCurrentCommentToTheLeft != null)
                {
                    rightCommentStart = ((Comment)commentsWithCurrentCommentToTheLeft.get(0)).getStartPosition();
                    String distanceString = sourceString.substring(commentEndPosition, rightCommentStart);
                    if(countLineSeparators(distanceString) >= 2)
                    {
                        commentsWithCurrentCommentToTheLeft = null;
                    }
                }
                if((commentsWithCurrentCommentToTheLeft != null) & (commentsWithCurrentCommentToTheLeft != commentList))
                {
                    commentRearangeTable.put(key, commentsWithCurrentCommentToTheLeft);
                    keysToBeDeleted.add(Integer.valueOf(commentEndPosition));
                    filterTable(leftInverted, commentRearangeTable, keysToBeDeleted);
                    int temp = ((Integer)equivalentKeysLeft.get(Integer.valueOf(commentEndPosition))).intValue();
                    equivalentKeysLeft.remove(Integer.valueOf(commentEndPosition));
                    equivalentKeysLeft.put(key, Integer.valueOf(temp));
                }
            }

        }

    }

    public void resolvedTransitiveRelationsRight(HashMap rightInverted)
    {
        Integer keyList[] = new Integer[0];
        keyList = (Integer[])rightInverted.keySet().toArray(keyList);
        Arrays.sort(keyList);
        Integer ainteger[];
        int j = (ainteger = keyList).length;
        for(int i = 0; i < j; i++)
        {
            Integer key = ainteger[i];
            HashMap commentRearangeTable = new HashMap();
            List keysToBeDeleted = new ArrayList();
            Comment comAr[] = new Comment[0];
            comAr = (Comment[])((List)rightInverted.get(key)).toArray(comAr);
            List commentList = (List)rightInverted.get(key);
            Comment acomment[];
            int l = (acomment = comAr).length;
            for(int k = 0; k < l; k++)
            {
                Comment comment = acomment[k];
                List commentsWithCurrentCommentToTheRight = (List)rightInverted.get(Integer.valueOf(comment.getStartPosition()));
                int commentStartPosition = comment.getStartPosition();
                int leftCommentEnd = 0;
                if(commentsWithCurrentCommentToTheRight != null)
                {
                    leftCommentEnd = ((Comment)commentsWithCurrentCommentToTheRight.get(0)).getStartPosition() + ((Comment)commentsWithCurrentCommentToTheRight.get(0)).getLength();
                    String distanceString = sourceString.substring(leftCommentEnd, commentStartPosition);
                    if(countLineSeparators(distanceString) >= 2)
                    {
                        commentsWithCurrentCommentToTheRight = null;
                    }
                }
                if((commentsWithCurrentCommentToTheRight != null) & (commentsWithCurrentCommentToTheRight != commentList))
                {
                    commentRearangeTable.put(key, commentsWithCurrentCommentToTheRight);
                    keysToBeDeleted.add(Integer.valueOf(commentStartPosition));
                    filterTable(rightInverted, commentRearangeTable, keysToBeDeleted);
                    int temp = ((Integer)equivalentKeysRight.get(Integer.valueOf(commentStartPosition))).intValue();
                    equivalentKeysRight.remove(Integer.valueOf(commentStartPosition));
                    equivalentKeysRight.put(key, Integer.valueOf(temp));
                }
            }

        }

    }

    private void filterTable(HashMap leftInverted, HashMap commentsWithCommentToTheLeftTable, List keysToBeDeleted)
    {
        Set toBeAddedSet = commentsWithCommentToTheLeftTable.entrySet();
        java.util.Map.Entry tableEntryToAdd;
        List originalList;
        for(Iterator iterator = toBeAddedSet.iterator(); iterator.hasNext(); leftInverted.put((Integer)tableEntryToAdd.getKey(), originalList))
        {
            tableEntryToAdd = (java.util.Map.Entry)iterator.next();
            originalList = (List)leftInverted.get(tableEntryToAdd.getKey());
            List commentsToBeAdded = (List)tableEntryToAdd.getValue();
            originalList.addAll(commentsToBeAdded);
            leftInverted.remove(tableEntryToAdd.getKey());
        }

        for(Iterator iterator1 = keysToBeDeleted.iterator(); iterator1.hasNext();)
        {
            Integer key = (Integer)iterator1.next();
            if(leftInverted.containsKey(key))
            {
                leftInverted.remove(key);
            }
        }

    }

    public void addEquivalentKeys(int distanceToTheLeft, int distanceToTheRight)
    {
        equivalentKeysLeft.put(Integer.valueOf(distanceToTheLeft), Integer.valueOf(distanceToTheRight));
        equivalentKeysRight.put(Integer.valueOf(distanceToTheRight), Integer.valueOf(distanceToTheLeft));
    }

}

